using System;
using DG.Tweening;
using Sirenix.OdinInspector;
using UnityEngine;
using UnityEngine.Events;
using UnityEngine.UI;

namespace DoTweenExtends
{
    public class TweenPlayer : BaseTween
    {
        [Title("Tween")]
        public TweenType type;

        [ShowIf("ShouldTransform", false)]
        [LabelText("Target")]
        public Transform transformTarget;

        [ShowIf("ShouldVectorEnum", false), EnumToggleButtons, HideLabel]
        public VectorType vectorType;

        [ShowIf("ShouldEffectType", false), EnumToggleButtons, HideLabel]
        public EffectType effectType = EffectType.Position;

        [ShowIf("ShouldFadeType", false), EnumToggleButtons, HideLabel]
        public FadeType fadeType;

        [ShowIf("ShouldCanvasGroup", false)]
        [LabelText("Target")]
        public CanvasGroup canvasGroupTarget;

        [ShowIf("ShouldGraphic", false)]
        [LabelText("Target")]
        public Graphic graphicTarget;

        [ShowIf("ShouldValue", false)]
        [LabelText("To")]
        public float toValue;

        [ShowIf("ShouldVector3", false)]
        [LabelText("To")]
        public Vector3 toVector3;

        [ShowIf("ShouldColor", false)]
        [LabelText("To")]
        public Color toColor = Color.white;

        public bool isFrom;

        [ShowIf("ShouldTransform", false)]
        public bool relative;

        [ShowIf("ShouldRotateMode", false)]
        public RotateMode rotateMode = RotateMode.Fast;

        [ShowIf("ShouldEffectType", false)]
        [Range(1, 50)]
        public int vibrato = 10;

        [ShowIf("type", TweenType.Shake)]
        [Range(0, 90)]
        public float randomness = 90f;

        [ShowIf("type", TweenType.Shake)]
        [Range(1, 100)]
        public float strength = 10;

        [ShowIf("type", TweenType.Shake)]
        public ShakeRandomnessMode shakeRandomness;

        [ShowIf("type", TweenType.Punch)]
        [Range(0, 1)]
        public float elasticity = 1f;

        public float duration = 1f;
        public bool speedBased;

        public Ease easeType = Ease.OutBack;

        [ShowIf("easeType", Ease.INTERNAL_Custom)]
        public AnimationCurve animationCurve = AnimationCurve.EaseInOut(0f, 0f, 1f, 1f);

        [Title("Events")]
        public EventType eventTypes;

        [ShowIf("ShouldCompleteEvent")]
        public UnityEvent onComplete;

        [ShowIf("ShouldStartEvent")]
        public UnityEvent onStart;

        [ShowIf("ShouldPlayEvent")]
        public UnityEvent onPlay;

        [ShowIf("ShouldPauseEvent")]
        public UnityEvent onPause;

        [ShowIf("ShouldRewindEvent")]
        public UnityEvent onRewind;

        [ShowIf("ShouldUpdateEvent")]
        public UnityEvent onUpdate;

        [ShowIf("ShouldKillEvent")]
        public UnityEvent onKill;

        protected override Tween CreateTween()
        {
            Tweener tween = null;

            switch (type)
            {
                case TweenType.Move:
                    if (transformTarget == null)
                    {
                        Debug.LogError("transformTarget is null!", this);
                        return null;
                    }

                    switch (vectorType)
                    {
                        case VectorType.All:
                            tween = transformTarget.DOMove(toVector3, duration);
                            break;
                        case VectorType.X:
                            tween = transformTarget.DOMoveX(toValue, duration);
                            break;
                        case VectorType.Y:
                            tween = transformTarget.DOMoveY(toValue, duration);
                            break;
                        case VectorType.Z:
                            tween = transformTarget.DOMoveZ(toValue, duration);
                            break;
                        default:
                            Debug.LogError($"Invalid VectorType: {vectorType}", this);
                            return null;
                    }
                    break;

                case TweenType.LocalMove:
                    if (transformTarget == null)
                    {
                        Debug.LogError("transformTarget is null!", this);
                        return null;
                    }

                    switch (vectorType)
                    {
                        case VectorType.All:
                            tween = transformTarget.DOLocalMove(toVector3, duration);
                            break;
                        case VectorType.X:
                            tween = transformTarget.DOLocalMoveX(toValue, duration);
                            break;
                        case VectorType.Y:
                            tween = transformTarget.DOLocalMoveY(toValue, duration);
                            break;
                        case VectorType.Z:
                            tween = transformTarget.DOLocalMoveZ(toValue, duration);
                            break;
                        default:
                            Debug.LogError($"Invalid VectorType: {vectorType}", this);
                            return null;
                    }
                    break;

                case TweenType.Scale:
                    if (transformTarget == null)
                    {
                        Debug.LogError("transformTarget is null!", this);
                        return null;
                    }

                    switch (vectorType)
                    {
                        case VectorType.All:
                            tween = transformTarget.DOScale(toVector3, duration);
                            break;
                        case VectorType.X:
                            tween = transformTarget.DOScaleX(toValue, duration);
                            break;
                        case VectorType.Y:
                            tween = transformTarget.DOScaleY(toValue, duration);
                            break;
                        case VectorType.Z:
                            tween = transformTarget.DOScaleZ(toValue, duration);
                            break;
                        default:
                            Debug.LogError($"Invalid VectorType: {vectorType}", this);
                            return null;
                    }
                    break;

                case TweenType.Rotate:
                    if (transformTarget == null)
                    {
                        Debug.LogError("transformTarget is null!", this);
                        return null;
                    }
                    tween = transformTarget.DORotate(toVector3, duration, rotateMode);
                    break;

                case TweenType.LocalRotate:
                    if (transformTarget == null)
                    {
                        Debug.LogError("transformTarget is null!", this);
                        return null;
                    }
                    tween = transformTarget.DOLocalRotate(toVector3, duration, rotateMode);
                    break;

                case TweenType.Fade:
                    switch (fadeType)
                    {
                        case FadeType.CanvasGroup:
                            if (canvasGroupTarget == null)
                            {
                                Debug.LogError("canvasGroupTarget is null!", this);
                                return null;
                            }
                            tween = canvasGroupTarget.DOFade(toValue, duration);
                            break;
                        case FadeType.Graphic:
                            if (graphicTarget == null)
                            {
                                Debug.LogError("graphicTarget is null!", this);
                                return null;
                            }
                            tween = graphicTarget.DOFade(toValue, duration);
                            break;
                        default:
                            Debug.LogError($"Invalid FadeType: {fadeType}", this);
                            return null;
                    }
                    break;

                case TweenType.Color:
                    if (graphicTarget == null)
                    {
                        Debug.LogError("graphicTarget is null!", this);
                        return null;
                    }
                    tween = graphicTarget.DOColor(toColor, duration);
                    break;

                case TweenType.AnchorPos:
                    if (transformTarget == null)
                    {
                        Debug.LogError("transformTarget is null!", this);
                        return null;
                    }

                    if (transformTarget is RectTransform rect)
                    {
                        switch (vectorType)
                        {
                            case VectorType.All:
                                tween = rect.DOAnchorPos(toVector3, duration);
                                break;
                            case VectorType.X:
                                tween = rect.DOAnchorPosX(toValue, duration);
                                break;
                            case VectorType.Y:
                                tween = rect.DOAnchorPosY(toValue, duration);
                                break;
                            case VectorType.Z:
                                Debug.LogError("Z axis not supported for AnchorPos", this);
                                return null;
                            default:
                                Debug.LogError($"Invalid VectorType: {vectorType}", this);
                                return null;
                        }
                    }
                    else
                    {
                        Debug.LogError("transformTarget is not a RectTransform", this);
                        return null;
                    }
                    break;

                case TweenType.Punch:
                    if (transformTarget == null)
                    {
                        Debug.LogError("transformTarget is null!", this);
                        return null;
                    }

                    switch (effectType)
                    {
                        case EffectType.Position:
                            tween = transformTarget.DOPunchPosition(toVector3, duration, vibrato, elasticity);
                            break;
                        case EffectType.Rotation:
                            tween = transformTarget.DOPunchRotation(toVector3, duration, vibrato, elasticity);
                            break;
                        case EffectType.Scale:
                            tween = transformTarget.DOPunchScale(toVector3, duration, vibrato, elasticity);
                            break;
                        default:
                            Debug.LogError($"Invalid EffectType: {effectType}", this);
                            return null;
                    }
                    break;

                case TweenType.Shake:
                    if (transformTarget == null)
                    {
                        Debug.LogError("transformTarget is null!", this);
                        return null;
                    }

                    switch (effectType)
                    {
                        case EffectType.Position:
                            tween = transformTarget.DOShakePosition(duration, strength, vibrato, randomness, false, true, shakeRandomness);
                            break;
                        case EffectType.Rotation:
                            tween = transformTarget.DOShakeRotation(duration, strength, vibrato, randomness, true, shakeRandomness);
                            break;
                        case EffectType.Scale:
                            tween = transformTarget.DOShakeScale(duration, strength, vibrato, randomness, true, shakeRandomness);
                            break;
                        default:
                            Debug.LogError($"Invalid EffectType: {effectType}", this);
                            return null;
                    }
                    break;

                default:
                    Debug.LogError($"Unsupported TweenType: {type}", this);
                    return null;
            }

            if (tween != null)
            {
                if (speedBased)
                    tween.SetSpeedBased(true);

                if (isFrom)
                    tween.From();
                if (relative)
                    tween.SetRelative();
                if (easeType == Ease.INTERNAL_Custom)
                    tween.SetEase(animationCurve);
                else
                    tween.SetEase(easeType);

                tween.OnStart(() => onStart?.Invoke());
                tween.OnPlay(() => onPlay?.Invoke());
                tween.OnPause(() => onPause?.Invoke());
                tween.OnRewind(() => onRewind?.Invoke());
                tween.OnUpdate(() => onUpdate?.Invoke());
                tween.OnComplete(() => onComplete?.Invoke());
                tween.OnKill(() => onKill?.Invoke());
            }

            return tween;
        }

        #region Editor Helpers

        private bool ShouldCompleteEvent()
        {
            return (eventTypes & EventType.OnComplete) == EventType.OnComplete;
        }

        private bool ShouldStartEvent()
        {
            return (eventTypes & EventType.OnStart) == EventType.OnStart;
        }

        private bool ShouldPlayEvent()
        {
            return (eventTypes & EventType.OnPlay) == EventType.OnPlay;
        }

        private bool ShouldPauseEvent()
        {
            return (eventTypes & EventType.OnPause) == EventType.OnPause;
        }

        private bool ShouldRewindEvent()
        {
            return (eventTypes & EventType.OnRewind) == EventType.OnRewind;
        }

        private bool ShouldUpdateEvent()
        {
            return (eventTypes & EventType.OnUpdate) == EventType.OnUpdate;
        }

        private bool ShouldKillEvent()
        {
            return (eventTypes & EventType.OnKill) == EventType.OnKill;
        }

        private bool ShouldTransform()
        {
            return type == TweenType.Move ||
                   type == TweenType.LocalMove ||
                   type == TweenType.Scale ||
                   type == TweenType.Rotate ||
                   type == TweenType.LocalRotate ||
                   type == TweenType.AnchorPos ||
                   type == TweenType.Shake ||
                   type == TweenType.Punch;
        }

        private bool ShouldGraphic()
        {
            return (type == TweenType.Fade && fadeType == FadeType.Graphic) ||
                   type == TweenType.Color;
        }

        private bool ShouldCanvasGroup()
        {
            return type == TweenType.Fade && fadeType == FadeType.CanvasGroup;
        }

        private bool ShouldEffectType()
        {
            return type == TweenType.Punch ||
                   type == TweenType.Shake;
        }

        private bool ShouldVectorEnum()
        {
            return type != TweenType.Color &&
                   type != TweenType.Rotate&&
                   type != TweenType.LocalRotate &&
                   type != TweenType.Fade &&
                   type != TweenType.Punch &&
                   type != TweenType.Shake;
        }

        private bool ShouldFadeType()
        {
            return type == TweenType.Fade;
        }

        private bool ShouldColor()
        {
            return type == TweenType.Color;
        }

        private bool ShouldVector3()
        {
            bool b = ((type == TweenType.Move || type == TweenType.LocalMove || type == TweenType.Scale || type == TweenType.AnchorPos) && vectorType == VectorType.All) || 
                     type == TweenType.Rotate ||
                     type == TweenType.LocalRotate ||
                     type == TweenType.Shake || 
                     type == TweenType.Punch;
            return b;
        }

        private bool ShouldValue()
        {
            bool fade = type == TweenType.Fade;
            bool value = (type == TweenType.Move || type == TweenType.LocalMove || type == TweenType.Scale || type == TweenType.AnchorPos) && vectorType != VectorType.All;
            return fade || value;
        }

        private bool ShouldRotateMode()
        {
            return type == TweenType.Rotate || type == TweenType.LocalRotate;
        }

        #endregion
    }
}